use std::any::Any;
use actix_web::middleware::{ErrorHandlerResponse, ErrorHandlers, Logger};
use actix_web::{dev, http::StatusCode, web, App, HttpResponse, HttpServer, Result, Responder};

use dotenv::dotenv;
use std::env;
use std::sync::Arc;
use serde_json::json;
use crate::business::auto_services::apps_auto_service;
use crate::extends::core::cached::redis_manager::RedisManager;
use crate::extends::core::config::app_ctx_handler::AppCtxHandler;
use crate::extends::core::context::app_context_beans::AppContextBeans;
use crate::extends::core::db::db_manager::DatabaseManager;
use crate::extends::core::initialize::banner as Banner;
use crate::extends::core::logger::log_handler::LogHandler;
use crate::extends::utils::request_util::RequestUtil;

mod apps;
mod business;
mod extends;

// Include the generated routes file from src/apps directory
include!("apps/auto_routes.rs");

// Define a route for health check
async fn health() -> impl Responder {
    HttpResponse::Ok().body("This server is very healthy!")
}


// Default route handler for 404 responses
async fn default_route() -> impl Responder {
    HttpResponse::NotFound().json(json!({"code": 404, "message": "Not Found"}))
}

// Custom error handler for 500 responses
fn render_500<B>(mut res: dev::ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> {
    res.response_mut().headers_mut().insert(
        http::header::CONTENT_TYPE,
        http::HeaderValue::from_static("Error"),
    );
    // TODO 暂时没有找到可以返回body错误信息的方法
    Ok(ErrorHandlerResponse::Response(res.map_into_left_body()))
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    dotenv().ok(); // Load environment variables from .env file

    // Read application configuration from YAML file
    let app_ctx_config = AppCtxHandler::load_config();

    // Initialize logger
    let log_handler = LogHandler::new(&app_ctx_config.framework.logging.path, log::LevelFilter::Info);
    log_handler.initialize().expect("Failed to initialize logger");

    // Initialize banner with application configuration
    let base_path = env::current_dir().unwrap();
    Banner::init_banner(
        &String::from(base_path.display().to_string() + "/banner.txt"),
        &app_ctx_config.clone(),
    );

    // Create a MySQL connection pool
    let db_pool = DatabaseManager::init_mysql_pool(
        &app_ctx_config.framework.datasource.clone()
    ).await.expect("Failed to create database pool.");

    // Create a Redis connection pool
    let redis_pool = RedisManager::init_redis_pool(
        &app_ctx_config.framework.redis.clone()
    ).await.expect("Failed to create redis pool.");

    // Register All Service Beans
    let app_ctx_beans = apps_auto_service(db_pool.clone());

    // Construct host:port combination for server binding
    let run_address = format!(
        "{}:{}",
        &app_ctx_config.application.server.host,
        &app_ctx_config.application.server.port.to_string()
    );

    // Configure and start Actix web server
    let server = HttpServer::new(move || {
        App::new()
            .wrap(Logger::default())
            .app_data(web::Data::new(db_pool.clone())) // Share database pool across all routes
            .app_data(web::Data::new(redis_pool.clone()))
            .app_data(web::Data::new(app_ctx_config.clone())) // Share app configuration across all routes
            .app_data(web::Data::new(app_ctx_beans.clone()))
            .configure(apps::auto_routes::apps_auto_routes) // Configure API routes
            .default_service(web::route().to(default_route)) // Default route for handling 404
            .route("/", web::get().to(HttpResponse::InternalServerError)) // Health check endpoint
            .wrap(
                ErrorHandlers::new()
                    .handler(StatusCode::INTERNAL_SERVER_ERROR, render_500),
            )
    })
        .bind(&run_address)? // Bind server to host:port
        .run(); // Start the server

    log::info!("Starting HTTP server at http://{}", &run_address);
    server.await?; // Await server startup

    Ok(()) // Return Ok if server starts successfully
}
